package cn.llyong.rpc.client.netty;

import cn.llyong.rpc.common.bo.RpcRequest;
import cn.llyong.rpc.common.bo.RpcResponse;
import cn.llyong.rpc.common.config.MonkeyRpcProperties;
import cn.llyong.rpc.common.discovery.ServiceDiscovery;
import cn.llyong.rpc.common.exception.RpcException;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import cn.llyong.rpc.client.handler.RpcClientHandler;
import cn.llyong.rpc.client.loadbalance.LoadBalanceContext;
import cn.llyong.rpc.client.loadbalance.RoundLoadBalance;
import java.util.List;
import java.util.concurrent.SynchronousQueue;

/**
 * @description:
 * @author: lvyong
 * @date: 2020年06月28日 15:53
 */
@Component
public class RpcClient {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ServiceDiscovery serviceDiscovery;

    @Autowired
    private NettyConfig nettyConfig;

    @Autowired
    private LoadBalanceContext balanceContext;

    @Autowired
    private MonkeyRpcProperties rpcProperties;

    public RpcClient() {
    }

    public RpcResponse execute(RpcRequest request) throws Exception {
        List<String> serviceList = serviceDiscovery.discovery(request.getAppName());
        if (CollectionUtils.isEmpty(serviceList)) {
            throw new RpcException("没有发现【"+ request.getAppName() + "】可用的服务");
        }
        String host;

        String balance = rpcProperties.getBalance();
        if (balance == null || balance == "") {
            RoundLoadBalance roundLoadBalance = new RoundLoadBalance();
            host = roundLoadBalance.chose(serviceList);
        } else {
            host = balanceContext.executeLoadBalance(balance, serviceList);
        }

        String[] h = host.split(":");
        ChannelPool channelPool = new ChannelPool(nettyConfig.poolConfig(), h[0], Integer.parseInt(h[1]));

        NettyChannel nettyChannel = channelPool.getResource();

        Channel channel = nettyChannel.getChannel();

        SynchronousQueue<Object> queue = new RpcClientHandler().send(request, channel);
        RpcResponse response = (RpcResponse) (queue.take());
//        channelPool.returnResource(nettyChannel);
        return response;
    }
}

